import React, {FC, Fragment, useContext, useEffect, useMemo, useRef, useState} from 'react';
import "./JournalArticleDetail.less";
import {Breadcrumb, Typography, Empty, message, Spin, Image, Tooltip, GetProps, TooltipProps, Skeleton, Button, Popover, QRCode, Watermark} from "antd";
import {useRequest} from "ahooks";
import * as API from "@/services";
import {HxConfigContext} from "@/layouts/HxConfigContext";
import {correspVal, getArticleLocationStr} from "@/utils/biz";
import dayjs from "dayjs";
import HxIcon from "@/components/HxIcon";
import classNames from "classnames";
import {FormattedMessage, Link, history, useAccess, useParams, useIntl} from "umi";
import {JournalDetailContext} from "@/pages/JournalPage/JournalDetail/commons/JournalDetailContext";
import useAuthedCheck from "@/components/hooks/UseAuthedCheck";
import useJatsTransformer from "@/pages/JournalPage/JournalDetail/commons/useJatsTransformer";
import tablePlaceholderImgUrl from "../../../assets/img/table-icon.gif"
import {getAuthToken} from "@/utils/auth";
import {ChartHtmlItem, createImgFallback, createSupTooltip} from "@/pages/JournalPage/JournalDetail/commons/JournalArticleUtil";
import lodash from "lodash";
import queryString from 'query-string';
import JournalArticleShare from "@/pages/JournalPage/JournalDetail/commons/JournalArticleShare";
import JournalArticleQuote from "@/pages/JournalPage/JournalDetail/commons/JournalArticleQuote";
import useJournalArticleHelp from "@/pages/JournalPage/JournalDetail/commons/useJournalArticleHelp";

interface JournalArticlesCitedProps {
  data?: API.ArticlesCitedInfo;
}

const JournalArticlesCited: FC<JournalArticlesCitedProps> = (props) => {
  const {data} = props;
  if (!data || data.citedByArticles.length === 0) {
    return <Empty/>
  }

  const recordsGroups = lodash.groupBy(data.citedByArticles, (d) => {
    if (d.articleType === "journal") {
      return "期刊类型引用";
    }
    return d.articleType || "其他类型引用";
  });

  return (
    <div className={"journal_articles_cited_container"}>
      {
        Object
          .keys(recordsGroups)
          .sort((a, b) => {
            // 如果 a 是 "其他类型引用"，将其排到最后
            if (a === "其他类型引用") return 1;
            if (b === "其他类型引用") return -1;
            // 其他情况按默认字典序排序
            return a.localeCompare(b);
          })
          .map(key => {
            const records = recordsGroups[key];
            return (
              <div key={key} className={"journal_articles_cited_group"}>
                <div className={"journal_articles_cited_group_title"}>{key}</div>
                <div className={"journal_articles_cited_group_content"}>
                  <ol>
                    {
                      records.map((d, index) => {
                        return (
                          <li key={index} className={"journal_articles_cited_item"}>
                            <div className={"journal_articles_cited_item_title"}>
                              {d.citiation}
                            </div>
                          </li>
                        )
                      })
                    }
                  </ol>
                </div>
              </div>
            )
          })
      }
    </div>
  );
};


interface JournalArticleDetailProps {
}

/**
 * 文章详情 页面
 */
const JournalArticleDetail: FC<JournalArticleDetailProps> = (props) => {
  const urlParams = useParams();
  const articleId = urlParams["*"];

  const intl = useIntl();
  const access = useAccess();
  const authedCheck = useAuthedCheck();
  const {isZhCN, siteInfo, authedRedirect} = useContext(HxConfigContext);

  const [chartHtmlItems, setChartHtmlItems] = useState<ChartHtmlItem[]>([]);
  const [chartOpenIndex, setChartOpenIndex] = useState<number | undefined>();

  const {journalId} = useContext(JournalDetailContext)
  const [navActive, setNavActive] = useState<string>("abstract")
  const dataReq = useRequest(() => API.queryFrontArticle(articleId!, true), {
    ready: !!articleId,
    refreshDeps: [articleId],
    onSuccess: (data) => {
      citedReq.run({
        articleId: data.data.id,
        journalAbbreviation: data.data.journal.journalAbbreviation
      })
    },
  });

  const citedReq = useRequest(p => API.queryFrontArticleCitedBy(p.articleId!, p.journalAbbreviation), {
    manual: true
  });


  const article = dataReq.data?.data;
  const {downloadArticlePdf, downloadArticlePdfIcon, downloading, favArticle, favIcon, doiUrl} = useJournalArticleHelp(article);

  if (!!article?.journal?.id && article.journal.id !== journalId) {
    //重定向到源期刊
    history.replace(`/journal/${article.journal.id}/article/${articleId}`)
  }

  const journalName = correspVal(isZhCN, article?.journal?.journalNameCn || article?.journalNameCn, article?.journal?.journalNameEn || article?.journalNameEn);

  const {htmlResult, error: xmlError, loading: xmlLoading} = useJatsTransformer({
    xmlUrl: article?.articleXmlUrl,
    //imgUrlPrefix: article?.imgUrlPrefix,
    imgUrlPrefix: "",
  })

  const articleRef = useRef<HTMLDivElement>(null);
  useEffect(() => {
    const target = articleRef.current;
    if (!target || !article) return;

    // 1. 创建观察者实例，定义变化发生时的回调
    // 创建 MutationObserver 监听 DOM 变化
    const observer = new MutationObserver((mutations) => {
      const imgMapping = (article.attachmentFigure || []).map((figure) => {
        //figure.imgUrl: http://hxqksdev.oss-cn-shenzhen.aliyuncs.com/yth_jyx/f214dc23864215e86c8a86e5ec88cd6f.jpg?originalFilename=202503093.jpg&df=1 或者
        const {query: imgUrlQuery} = queryString.parseUrl(figure.imgUrl)
        return {
          name: imgUrlQuery["originalFilename"] as string,
          url: figure.imgUrl!,
        };
      }).reduce((acc, curr) => {
        if (curr.name) {
          acc[curr.name!] = curr.url;
        }
        return acc;
      }, {} as Record<string, string>);


      //图片fallback处理
      const imgs = target.querySelectorAll('.jats-article img');
      imgs.forEach(img => {
        createImgFallback(img as HTMLImageElement, imgMapping)
      })

      //上标文本, 默认点击后会移动对应的参考文献, 这里改成Tooltip的形式
      const fulltextSups = target.querySelectorAll('.journal-article-fulltext sup');
      const references = target.querySelectorAll('.journal-article-reference > .ref-list >.row');
      fulltextSups.forEach(sup => {
        createSupTooltip(sup as HTMLElement, references)
      })

      // 监听所有 href 以 # 开头的 a 标签点击事件
      const anchors = target.querySelectorAll('a[href^="#"]');
      anchors.forEach(anchor => anchor.addEventListener('click', (e) => {
        e.preventDefault();
        // 获取 href 中的目标 ID（如 "#Table3" 提取为 "Table3"）
        const targetId = anchor.getAttribute('href')?.substring(1);
        if (!targetId) return; // 如果是 "#" 则不处理
        // 获取目标元素
        const targetElement = document.getElementById(targetId);
        if (!targetElement) return; // 目标元素不存在则退出

        // 设置垂直偏移量（根据需要调整，例如导航栏高度为 80px）
        const offset = 80;
        // 计算目标元素的顶部位置 + 偏移量
        const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - offset;
        // 平滑滚动到目标位置
        window.scrollTo({
          top: targetPosition,
          behavior: 'smooth' // 平滑滚动效果，可选
        });
      }))

      // 图表tab中的图表
      const panels = target.querySelectorAll('.journal-article-chart .panel');
      if (panels.length > 0) {
        const htmls: ChartHtmlItem[] = [];
        //全文tab中的图表
        const fulltextPanels = target.querySelectorAll('.journal-article-fulltext .panel');
        //图表点击事件
        const addPanelListener = (element: Element | null, chartOpenIndex: number) => {
          const downloadLink = element?.querySelector(".panel-header-extra a");
          //下载
          downloadLink?.addEventListener('click', (e) => {
            e.stopPropagation();  //停止冒泡
            const isCsvDownload = downloadLink.classList.contains("table-csv-download");
            if (isCsvDownload) {
              e.preventDefault();
              // html table转换为csv
              const table = element?.querySelector('.panel-content > table');
              if (table) {
                let csv = '';
                const rows = table.querySelectorAll('tr');
                rows.forEach(row => {
                  const cols = row.querySelectorAll('th, td');
                  const rowData = Array.from(cols).map(col => {
                    let data = col.textContent?.replace(/"/g, '""') || '';
                    if (data.includes(',') || data.includes('\n') || data.includes('"')) {
                      data = `"${data}"`;
                    }
                    return data;
                  });
                  csv += rowData.join(',') + '\n';
                });
                // 添加 UTF-8 BOM, 不然excel打开中文会乱码
                const bom = new Uint8Array([0xef, 0xbb, 0xbf]);
                const blob = new Blob([bom, csv], {type: 'text/csv;charset=utf-8;'});

                const url = URL.createObjectURL(blob);
                // 获取标题作为文件名
                const capt = element?.querySelector('.panel-header .panel-caption > p');
                const allNodes = Array.from(capt?.childNodes || []) as HTMLElement[];
                const textNodesContent = allNodes
                  .map(node => {
                    if (node.nodeType === Node.TEXT_NODE) {
                      return node.textContent?.trim();
                    }
                    if (node.classList.contains("panel-label")) {
                      return node.outerText?.trim() + "_";
                    }
                    return node.outerText?.trim();
                  })
                  .filter(text => text) // 去除空字符串
                  .join("");

                //下载触发
                const link = document.createElement('a');
                link.setAttribute('href', url);
                link.setAttribute('download', `${textNodesContent || "table_data"}.csv`);
                link.style.visibility = 'hidden';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
              }
            }
          });
          //预览打开
          element?.addEventListener('click', (e) => {
            e.preventDefault();
            setChartOpenIndex(chartOpenIndex);
          });
        };

        panels.forEach((panel, panelIndex) => {
            //panel的说明描述
            const caption = panel.querySelector('.panel-header-title  div.panel-caption')?.cloneNode(true) as HTMLElement;
            //判断panel是否存在table-wrap的css
            const isTablePanel = panel.classList.contains('table-wrap');
            if (isTablePanel) {
              const table = panel.querySelector('.panel-content > table');
              htmls.push({
                type: "custom",
                caption: caption?.outerHTML,
                html: table?.outerHTML,
                src: tablePlaceholderImgUrl,
              })
            } else {
              const img = panel.querySelector('.panel-content > img');
              htmls.push({
                type: "img",
                caption: caption?.outerHTML,
                html: img?.outerHTML,
                src: img?.getAttribute('src') || tablePlaceholderImgUrl,
              })
            }
            //图表tab中的chart点击事件
            addPanelListener(panel, panelIndex);
            //全文tab中的chart点击事件
            addPanelListener(fulltextPanels[panelIndex], panelIndex);
          }
        );
        setChartHtmlItems(htmls);
      }
    });
    // 2. 配置监听选项（这里监听属性变化）
    const config = {
      // attributes: true, // 监听属性变化
      // attributeOldValue: true, // 记录变化前的旧值
      // 其他可选配置：
      childList: true, // 监听子节点增减
      subtree: true, // 监听所有后代节点
      // characterData: true, // 监听文本内容变化
    };
    // 3. 开始监听目标元素
    observer.observe(target, config);
    // 4. 组件卸载时停止监听（避免内存泄漏）
    return () => {
      observer.disconnect();
    };
  }, [article]);


  const journalCopyright = correspVal(isZhCN, siteInfo?.journalCopyright.textCn, siteInfo?.journalCopyright.textEn);
  const copyrightTip1 = intl.formatMessage({id: "journal.article-copyright.copyright"}, {journalName, journalCopyright});
  const copyrightTip2 = intl.formatMessage({id: "journal.article-copyright.without-auth-tip"});


  return (
    <Skeleton loading={dataReq.loading} active={true} paragraph={{rows: 10, width: "100%"}}>
      <div className={"journal-article-detail-container"}>
        <Breadcrumb
          className={"journal-article-breadcrumd"}
          items={[
            {title: (<Link to={`/journal/${article?.journal?.id || article?.journalId}/archive`}>{journalName}</Link>)},
            {title: getArticleLocationStr(article)}
          ]}
        />
        <div className={"journal-article-page"}>
          <div className={"journal-article-page-header"}>
            <div className={"journal-article-title"}
                 dangerouslySetInnerHTML={
                   {__html: correspVal(isZhCN, article?.articleTitleCn, article?.articleTitleEn) || ""}
                 }
            />
            <div className={"journal-article-subtitle"}>
              <div className={"journal-article-source"}>
                <div><span><FormattedMessage id="article.source"/>: </span>{journalName}|{getArticleLocationStr(article)}</div>
                <div><span><FormattedMessage
                  id="article.online-release-time"/>: </span>{dayjs(article?.articlePublishedDate, 'YYYY-MM-DD HH:mm:ss')?.format('YYYY-MM-DD')}</div>
              </div>
              <div className={"journal-article-sp-stats"}>
                <div><span><FormattedMessage id="stats.visits"/>: </span>{(article?.accessNum || 0) + (article?.hitsnum || 0)}</div>
                <div><span><FormattedMessage id="stats.downloads"/>: </span>{(article?.downloadNum || 0)}</div>
                <div><span><FormattedMessage id="stats.citation"/>: </span>{article?.citingArticleNum}</div>
              </div>
            </div>
            <div className={"journal-article-meta"}>
              <div className={"journal-article-meta-left"}>
                <div className={"ja-meta-item"}><span><FormattedMessage
                  id="article.author"/>: </span>{correspVal(isZhCN, article?.articleAuthorCn, article?.articleAuthorEn)}</div>
                <div className={"ja-meta-item"}><span><FormattedMessage id="article.keywords"/>: </span>
                  <div className={"ja-meta-tags"}>
                    {
                      correspVal(isZhCN, article?.articleKeywordCn, article?.articleKeywordEn)
                        ?.split("|")
                        ?.map(keyword => <div key={keyword}>{keyword}</div>)
                    }
                  </div>
                </div>
                <div className={"ja-meta-item"} onDoubleClick={(e) => {
                  e.preventDefault();
                  window.open(doiUrl)
                }}><span>DOI: </span>{article?.articleDoi}</div>
              </div>
              <div className={"journal-article-meta-right"}>
                <Popover trigger={"click"} content={
                  <QRCode size={100}
                          color={"#000"}
                          bgColor={"#FFF"}
                          bordered={false}
                          iconSize={25}
                          icon="/qrcode_icon.png"
                          value={window.location.href}/>
                }>
                  <Button className={"journal-article-meta-btn"}>
                    <HxIcon type={"hxicon-daochu1"}/> <FormattedMessage id="text.export"/>
                  </Button>
                </Popover>
                <Button className={"journal-article-meta-btn"} loading={downloading} onClick={(e) => {
                  e.preventDefault();
                  downloadArticlePdf();
                }}>{downloadArticlePdfIcon} <FormattedMessage id="text.download"/></Button>
                <Button className={"journal-article-meta-btn"} onClick={(e) => {
                  e.preventDefault();
                  favArticle((art) => {
                    dataReq.mutate({
                      ...dataReq.data,
                      data: art
                    } as API.RespResult<API.FrontArticle>)
                  });
                }}> {favIcon} <FormattedMessage id="text.favorite"/></Button>
                <Popover trigger={"click"} content={
                  <JournalArticleShare article={article}/>
                }>
                  <Button className={"journal-article-meta-btn"}>
                    <HxIcon type={"hxicon-code"}/> <FormattedMessage id="text.scan-code"/>
                  </Button>
                </Popover>
                <Popover trigger={"click"}
                         content={(
                           <JournalArticleQuote article={article}/>
                         )}>
                  <Button className={"journal-article-meta-btn"}>
                    <HxIcon type={"hxicon-yinyong"}/> <FormattedMessage id="text.quote"/>
                  </Button>
                </Popover>

              </div>
            </div>
          </div>
          <Spin spinning={xmlLoading}>
            <div className={"journal-article-page-content"}>
              <ul className={"journal-article-navs"}>
                {/*<li><a className={classNames({"active": navActive === "all"})} onClick={() => setNavActive("all")}>ALL</a></li>*/}
                <li><a className={classNames({"active": navActive === "abstract"})}
                       onClick={() => setNavActive("abstract")}><FormattedMessage id="article.abstract"/></a></li>
                <li><a className={classNames({"active": navActive === "fulltext"})} onClick={() => setNavActive("fulltext")}><FormattedMessage
                  id="article.fulltext"/> </a></li>
                <li>
                  <a className={classNames({"active": navActive === "chart"})} onClick={() => setNavActive("chart")}>
                    <FormattedMessage id="article.chart"/> {htmlResult?.chartTotal !== undefined ? `(${htmlResult?.chartTotal})` : ''}
                  </a>
                </li>
                <li>
                  <a className={classNames({"active": navActive === "video"})} onClick={() => setNavActive("video")}>
                    <FormattedMessage id="article.video"/> {article?.attachmentVideo !== undefined ? `(${article?.attachmentVideo?.length})` : ''}
                  </a>
                </li>
                <li>
                  <a className={classNames({"active": navActive === "reference"})} onClick={() => setNavActive("reference")}>
                    <FormattedMessage id="article.reference"/> {htmlResult?.referenceTotal !== undefined ? `(${htmlResult?.referenceTotal})` : ''}
                  </a>
                </li>
                <li>
                  <a className={classNames({"active": navActive === "cited"})} onClick={() => setNavActive("cited")}>
                    <FormattedMessage id="article.cited"/> {citedReq?.data?.data?.articleId !== undefined ? `(${citedReq?.data?.data?.citedCount || 0})` : ''}
                  </a>
                </li>
              </ul>

              <Watermark
                content={[copyrightTip1, copyrightTip2]}
                font={{
                  color: "rgba(0,0,0,.1)"
                }}
              >
                <div className={"jats-article"} ref={articleRef}>
                  {!xmlLoading && ((xmlError && navActive !== "video") ? (
                      <>
                        <a className={"resource-jump"} target="_blank" href={`https://doi.org/${article?.articleDoi}`}>
                          <FormattedMessage id="text.click-to-jump"/>
                        </a>
                      </>
                    )
                    :
                    (
                      <>
                        {/*<div className={classNames("journal-article-all", {"journal-article-part-hide": navActive !== "all"})}
                   dangerouslySetInnerHTML={{__html: htmlResult?.all || ""}}/>*/}
                        <div className={classNames("journal-article-part journal-article-abstract", {"journal-article-part-hide": navActive !== "abstract"})}>
                          <div dangerouslySetInnerHTML={{__html: correspVal(isZhCN, htmlResult?.abstrCn, htmlResult?.abstrEn) || ""}}/>

                        </div>

                        <div className={classNames("journal-article-part journal-article-fulltext", {"journal-article-part-hide": navActive !== "fulltext"})}
                             dangerouslySetInnerHTML={{__html: htmlResult?.fulltext || ""}}/>
                        <div className={classNames("journal-article-part journal-article-chart", {"journal-article-part-hide": navActive !== "chart"})}
                             dangerouslySetInnerHTML={{__html: htmlResult?.chart || ""}}/>
                        <div className={classNames("journal-article-part journal-article-reference", {"journal-article-part-hide": navActive !== "reference"})}
                             dangerouslySetInnerHTML={{__html: htmlResult?.reference || ""}}/>
                        {
                          navActive === "cited" && (
                            <div className={"journal-article-part journal-article-cited"}>
                              <JournalArticlesCited data={citedReq?.data?.data}/>
                            </div>
                          )
                        }
                      </>
                    ))}
                  {
                    navActive === "video" && (
                      <div className={"journal-article-part journal-article-video"}>
                        {
                          article?.attachmentVideo?.map((v, vindex) => {
                            return (
                              <div className={"jav-item"}>
                                <video key={vindex} src={v.fileUrl} poster={v.fileCoverUrl} controls={true}/>
                                <div className={"jav-item-title"}>{v.fileName}</div>
                              </div>
                            )
                          })
                        }
                      </div>
                    )
                  }
                  <div className={"journal-copyright-tip"}><span>  <FormattedMessage
                    id="journal.article-copyright.label"/>：</span>{`${copyrightTip1}，${copyrightTip2}`}</div>
                </div>
              </Watermark>

            </div>
          </Spin>

          <Image.PreviewGroup
            preview={{
              rootClassName: "journal-article-chart-preview-root",
              minScale: 0.3,
              destroyOnClose: true,
              visible: chartOpenIndex !== undefined,
              current: chartOpenIndex,
              onVisibleChange: (visible: boolean, prevVisible: boolean, current: number) => {
                console.log(visible, current)
                setChartOpenIndex(!visible ? undefined : current);
              },
              countRender: (current, total) => {
                const item = chartHtmlItems[current - 1];
                return (
                  <>
                    <div dangerouslySetInnerHTML={{__html: item?.caption || ""}}/>
                    <div>{current + 1} / {total}</div>
                  </>
                );
              },
              imageRender: (originalNode, info) => {
                const item = chartHtmlItems[info.current];
                if (!item) {
                  return null;
                }
                let previewContent: React.ReactNode | undefined;
                if (item.type === "img") {
                  previewContent = originalNode;
                } else {
                  previewContent = <div className={"jacp-custom-item"} dangerouslySetInnerHTML={{__html: item?.html || ""}}></div>
                }
                return previewContent;
                /*return (
                  <div>
                    <div>1112255</div>
                    {previewContent}
                  </div>
                );*/
              },
              toolbarRender: (originalNode, info) => {
                const item = chartHtmlItems[info.current];
                if (!item) {
                  return null;
                }
                if (item.type === "img") {
                  return originalNode;
                } else {
                  return null;
                }
              },
              onChange: (current, prev) => setChartOpenIndex(current),
            }}
            items={chartHtmlItems.map(item => {
              return {
                src: item.src,
                alt: item.caption,
                width: 500,
              }
            })}
          />
        </div>
      </div>
    </Skeleton>

  );
};

export default JournalArticleDetail;
